aboutsummaryrefslogtreecommitdiffstats
path: root/src/app/groups/[groupId]
diff options
context:
space:
mode:
authorSebastien Castiel <sebastien@castiel.me>2024-01-09 08:53:51 -0500
committerSebastien Castiel <sebastien@castiel.me>2024-01-09 08:53:51 -0500
commit1b9e624004cfb64135b744f877e5fa87e5810abd (patch)
treef1994b7c10d98410bdc73ca323d2c32e6e019bac /src/app/groups/[groupId]
parent6bd3299331265ea2a0c800e3c3199ad4e32ce8de (diff)
Ask the user who they are when opening a group for the first time (#7)
Diffstat (limited to 'src/app/groups/[groupId]')
-rw-r--r--src/app/groups/[groupId]/expenses/active-user-modal.tsx134
-rw-r--r--src/app/groups/[groupId]/expenses/expense-list.tsx14
-rw-r--r--src/app/groups/[groupId]/expenses/page.tsx80
3 files changed, 187 insertions, 41 deletions
diff --git a/src/app/groups/[groupId]/expenses/active-user-modal.tsx b/src/app/groups/[groupId]/expenses/active-user-modal.tsx
new file mode 100644
index 0000000..5d9d005
--- /dev/null
+++ b/src/app/groups/[groupId]/expenses/active-user-modal.tsx
@@ -0,0 +1,134 @@
+'use client'
+
+import { Button } from '@/components/ui/button'
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from '@/components/ui/dialog'
+import {
+ Drawer,
+ DrawerContent,
+ DrawerDescription,
+ DrawerFooter,
+ DrawerHeader,
+ DrawerTitle,
+} from '@/components/ui/drawer'
+import { Label } from '@/components/ui/label'
+import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
+import { getGroup } from '@/lib/api'
+import { useMediaQuery } from '@/lib/hooks'
+import { cn } from '@/lib/utils'
+import { ComponentProps, useEffect, useState } from 'react'
+
+type Props = {
+ group: NonNullable<Awaited<ReturnType<typeof getGroup>>>
+}
+
+export function ActiveUserModal({ group }: Props) {
+ const [open, setOpen] = useState(false)
+ const isDesktop = useMediaQuery('(min-width: 768px)')
+
+ useEffect(() => {
+ const tempUser = localStorage.getItem(`newGroup-activeUser`)
+ const activeUser = localStorage.getItem(`${group.id}-activeUser`)
+ if (!tempUser && !activeUser) {
+ setOpen(true)
+ }
+ }, [group])
+
+ function updateOpen(open: boolean) {
+ if (!open && !localStorage.getItem(`${group.id}-activeUser`)) {
+ localStorage.setItem(`${group.id}-activeUser`, 'None')
+ }
+ setOpen(open)
+ }
+
+ if (isDesktop) {
+ return (
+ <Dialog open={open} onOpenChange={updateOpen}>
+ <DialogContent className="sm:max-w-[425px]">
+ <DialogHeader>
+ <DialogTitle>Who are you?</DialogTitle>
+ <DialogDescription>
+ Tell us which participant you are to let us customize how the
+ information is displayed.
+ </DialogDescription>
+ </DialogHeader>
+ <ActiveUserForm group={group} close={() => setOpen(false)} />
+ <DialogFooter className="sm:justify-center">
+ <p className="text-sm text-center text-muted-foreground">
+ This setting can be changed later in the group settings.
+ </p>
+ </DialogFooter>
+ </DialogContent>
+ </Dialog>
+ )
+ }
+
+ return (
+ <Drawer open={open} onOpenChange={updateOpen}>
+ <DrawerContent>
+ <DrawerHeader className="text-left">
+ <DrawerTitle>Who are you?</DrawerTitle>
+ <DrawerDescription>
+ Tell us which participant you are to let us customize how the
+ information is displayed.
+ </DrawerDescription>
+ </DrawerHeader>
+ <ActiveUserForm
+ className="px-4"
+ group={group}
+ close={() => setOpen(false)}
+ />
+ <DrawerFooter className="pt-2">
+ <p className="text-sm text-center text-muted-foreground">
+ This setting can be changed later in the group settings.
+ </p>
+ </DrawerFooter>
+ </DrawerContent>
+ </Drawer>
+ )
+}
+
+function ActiveUserForm({
+ group,
+ close,
+ className,
+}: ComponentProps<'form'> & { group: Props['group']; close: () => void }) {
+ const [selected, setSelected] = useState('None')
+
+ return (
+ <form
+ className={cn('grid items-start gap-4', className)}
+ onSubmit={(event) => {
+ event.preventDefault()
+ localStorage.setItem(`${group.id}-activeUser`, selected)
+ close()
+ }}
+ >
+ <RadioGroup defaultValue="none" onValueChange={setSelected}>
+ <div className="flex flex-col gap-4 my-4">
+ <div className="flex items-center space-x-2">
+ <RadioGroupItem value="none" id="none" />
+ <Label htmlFor="none" className="italic font-normal flex-1">
+ I don’t want to select anyone
+ </Label>
+ </div>
+ {group.participants.map((participant) => (
+ <div key={participant.id} className="flex items-center space-x-2">
+ <RadioGroupItem value={participant.id} id={participant.id} />
+ <Label htmlFor={participant.id} className="flex-1">
+ {participant.name}
+ </Label>
+ </div>
+ ))}
+ </div>
+ </RadioGroup>
+ <Button type="submit">Save changes</Button>
+ </form>
+ )
+}
diff --git a/src/app/groups/[groupId]/expenses/expense-list.tsx b/src/app/groups/[groupId]/expenses/expense-list.tsx
index ef4903c..4578300 100644
--- a/src/app/groups/[groupId]/expenses/expense-list.tsx
+++ b/src/app/groups/[groupId]/expenses/expense-list.tsx
@@ -27,11 +27,15 @@ export function ExpenseList({
if (activeUser || newUser) {
localStorage.removeItem('newGroup-activeUser')
localStorage.removeItem(`${groupId}-newUser`)
- const userId = participants.find(
- (p) => p.name === (activeUser || newUser),
- )?.id
- if (userId) {
- localStorage.setItem(`${groupId}-activeUser`, userId)
+ if (activeUser === 'None') {
+ localStorage.setItem(`${groupId}-activeUser`, 'None')
+ } else {
+ const userId = participants.find(
+ (p) => p.name === (activeUser || newUser),
+ )?.id
+ if (userId) {
+ localStorage.setItem(`${groupId}-activeUser`, userId)
+ }
}
}
}, [groupId, participants])
diff --git a/src/app/groups/[groupId]/expenses/page.tsx b/src/app/groups/[groupId]/expenses/page.tsx
index 5285cb8..2a1ac5f 100644
--- a/src/app/groups/[groupId]/expenses/page.tsx
+++ b/src/app/groups/[groupId]/expenses/page.tsx
@@ -1,3 +1,4 @@
+import { ActiveUserModal } from '@/app/groups/[groupId]/expenses/active-user-modal'
import { ExpenseList } from '@/app/groups/[groupId]/expenses/expense-list'
import { Button } from '@/components/ui/button'
import {
@@ -24,45 +25,52 @@ export default async function GroupExpensesPage({
}: {
params: { groupId: string }
}) {
+ const group = await getGroup(groupId)
+ if (!group) notFound()
+
return (
- <Card className="mb-4">
- <div className="flex flex-1">
- <CardHeader className="flex-1">
- <CardTitle>Expenses</CardTitle>
- <CardDescription>
- Here are the expenses that you created for your group.
- </CardDescription>
- </CardHeader>
- <CardHeader>
- <Button asChild size="icon">
- <Link href={`/groups/${groupId}/expenses/create`}>
- <Plus />
- </Link>
- </Button>
- </CardHeader>
- </div>
+ <>
+ <Card className="mb-4">
+ <div className="flex flex-1">
+ <CardHeader className="flex-1">
+ <CardTitle>Expenses</CardTitle>
+ <CardDescription>
+ Here are the expenses that you created for your group.
+ </CardDescription>
+ </CardHeader>
+ <CardHeader>
+ <Button asChild size="icon">
+ <Link href={`/groups/${groupId}/expenses/create`}>
+ <Plus />
+ </Link>
+ </Button>
+ </CardHeader>
+ </div>
- <CardContent className="p-0">
- <Suspense
- fallback={[0, 1, 2].map((i) => (
- <div
- key={i}
- className="border-t flex justify-between items-center px-6 py-4 text-sm"
- >
- <div className="flex flex-col gap-2">
- <Skeleton className="h-4 w-16 rounded-full" />
- <Skeleton className="h-4 w-32 rounded-full" />
+ <CardContent className="p-0">
+ <Suspense
+ fallback={[0, 1, 2].map((i) => (
+ <div
+ key={i}
+ className="border-t flex justify-between items-center px-6 py-4 text-sm"
+ >
+ <div className="flex flex-col gap-2">
+ <Skeleton className="h-4 w-16 rounded-full" />
+ <Skeleton className="h-4 w-32 rounded-full" />
+ </div>
+ <div>
+ <Skeleton className="h-4 w-16 rounded-full" />
+ </div>
</div>
- <div>
- <Skeleton className="h-4 w-16 rounded-full" />
- </div>
- </div>
- ))}
- >
- <Expenses groupId={groupId} />
- </Suspense>
- </CardContent>
- </Card>
+ ))}
+ >
+ <Expenses groupId={groupId} />
+ </Suspense>
+ </CardContent>
+ </Card>
+
+ <ActiveUserModal group={group} />
+ </>
)
}